package mirrormonkey.framework.entity;

import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import mirrormonkey.framework.Updatable;
import mirrormonkey.framework.member.DynamicMemberData;
import mirrormonkey.framework.member.StaticMemberData;

public class StaticEntityData {

	public final Class<? extends SyncEntity> localClass;

	public final Class<? extends SyncEntity> connectedClass;

	public final Class<?>[] notifyClasses;

	protected final StaticMemberData[] membersById;

	protected final Updatable[] updatableMembers;

	protected final Map<MemberDataKey, StaticMemberData> membersByKey;

	protected final Collection<EntityData> entities;

	public StaticEntityData(Class<? extends SyncEntity> localClass,
			Class<? extends SyncEntity> connectedClass,
			StaticMemberData[] members, Class<?>[] notifyClasses) {
		this.localClass = localClass;
		this.connectedClass = connectedClass;
		this.membersById = members;
		membersByKey = new HashMap<MemberDataKey, StaticMemberData>();
		for (StaticMemberData data : members) {
			data.setStaticEntityData(this);
			membersByKey.put(data.getMemberKey(), data);
		}
		this.notifyClasses = notifyClasses;
		entities = new HashSet<EntityData>();
		List<Updatable> updatableMembers = new LinkedList<Updatable>();
		for (StaticMemberData i : members) {
			if (Updatable.class.isInstance(i)) {
				updatableMembers.add((Updatable) i);
			}
		}
		this.updatableMembers = updatableMembers
				.toArray(new Updatable[updatableMembers.size()]);
	}

	public DynamicMemberData[] createDynamicMemberData() {
		DynamicMemberData[] dynamicData = new DynamicMemberData[membersById.length];
		int id = 0;
		for (StaticMemberData i : membersById) {
			dynamicData[id++] = i.createDynamicData();
		}
		return dynamicData;
	}

	public <T extends StaticMemberData> T getData(int id, Class<T> castTo) {
		return (T) membersById[id];
	}

	public <T extends StaticMemberData> T getData(MemberDataKey key,
			Class<T> castTo) {
		return (T) membersByKey.get(key);
	}

	public boolean requiresUpdate() {
		return updatableMembers.length != 0;
	}

	public void update(float tpf) {
		for (Updatable i : updatableMembers) {
			i.update(tpf);
		}
	}

	public void addEntity(EntityData data) {
		entities.add(data);
	}

	public void removeEntity(EntityData data) {
		entities.remove(data);
	}

	@Override
	public String toString() {
		return "[" + super.toString() + ": local=" + localClass.getName()
				+ ", connected=" + connectedClass.getName() + "]";
	}

	public static interface MemberDataKey {
	}

}
